using System;
using System.Collections.Generic;
using System.Text;
using Zsa.Emulation.Input;
using Zsa.Emulation.Util;

namespace Zsa.Emulation.Render.Input
{
    /// <summary>
    /// The controller device manager.
    /// </summary>
    public abstract class ControllerDeviceManager :
        RenderDevice<ControllerDeviceCapabilities, ControllerSettings, ControllerDeviceManager>
    {
        #region Fields
        /// <summary>
        /// The input register for port one.
        /// </summary>
        private InputRegister _RegisterOne;

        /// <summary>
        /// the input register for port two
        /// </summary>
        private InputRegister _RegisterTwo;

        /// <summary>
        /// The buffer for player one.
        /// </summary>
        private byte _InputOneBuffer = 0;

        /// <summary>
        /// The buffer for player three.
        /// </summary>
        private byte _InputThreeBuffer = 0;

        /// <summary>
        /// The buffer for player two.
        /// </summary>
        private byte _InputTwoBuffer = 0;

        /// <summary>
        /// The buffer for player four.
        /// </summary>
        private byte _InputFourBuffer = 0;

        #endregion Fields

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="T:ControllerDeviceManager"/> class.
        /// </summary>
        /// <param name="settings"></param>
        protected ControllerDeviceManager(ControllerSettings settings)
            : base(settings)
        {
        }
        #endregion Constructor

        #region Methods
        /// <summary>
        /// Processes the controls.
        /// </summary>
        public virtual void ProcessControls()
        {
            //TraceLogger.TraceInformation(TraceSubsystem.Controller, "Processing Controls");

            _RegisterOne._RegisterOne = _InputOneBuffer;
            _RegisterOne._RegisterTwo = _InputThreeBuffer;

            _RegisterTwo._RegisterOne = _InputTwoBuffer;
            _RegisterTwo._RegisterTwo = _InputFourBuffer;

            #if DEBUG
            if (_InputOneBuffer != 0)
            {
                TraceLogger.TraceInformation(TraceSubsystem.Controller,
                    "Input Buffer Processed : Device {0} Buttons : {1}",
                    0,
                    (NesInputButton)_InputOneBuffer
                );
            }

            if (_InputTwoBuffer != 0)
            {
                TraceLogger.TraceInformation(TraceSubsystem.Controller,
                    "Input Buffer Processed : Device {0} Buttons : {1}",
                    2,
                    (NesInputButton)_InputTwoBuffer
                );
            }

            if (_InputThreeBuffer != 0)
            {
                TraceLogger.TraceInformation(TraceSubsystem.Controller,
                    "Input Buffer Processed : Device {0} Buttons : {1}",
                    3,
                    (NesInputButton)_InputThreeBuffer
                );
            }

            if (_InputFourBuffer != 0)
            {
                TraceLogger.TraceInformation(TraceSubsystem.Controller,
                    "Input Buffer Processed : Device {0} Buttons : {1}",
                    4,
                    (NesInputButton)_InputFourBuffer
                );
            }

            #endif

            // clear the buffers.
            //_InputOneBuffer = 0;
            //_InputTwoBuffer = 0;
            //_InputThreeBuffer = 0;
            //_InputFourBuffer = 0;

        }

        /// <summary>
        /// Neses the key pressed.
        /// </summary>
        /// <param name="deviceNumber">The device number.</param>
        /// <param name="button">The button.</param>
        protected void NesKeyPressed(byte deviceNumber, NesInputButton button)
        {
          //  Console.WriteLine("{0} {1}", deviceNumber, button);
            switch (deviceNumber)
            {
                case 0:
                    _InputOneBuffer |= ((byte)(1 << ((byte)button-1)));
                    break;
                case 1:
                    _InputTwoBuffer |= (byte)(1 << ((byte)button - 1));
                    break;
                case 2:
                    _InputThreeBuffer |= (byte)(1 << ((byte)button - 1));
                    break;
                case 3:
                    _InputFourBuffer |= (byte)(1 << ((byte)button - 1));
                    break;
                default:
                    throw new ArgumentOutOfRangeException("deviceNumber");
            }

            #if DEBUG 
            TraceLogger.TraceInformation(TraceSubsystem.Controller,
                "Input Buffer Write : Device {0} Button : {1}",
                deviceNumber,
                button
            );
            #endif
        }
        protected void NesKeyReleased(byte deviceNumber, NesInputButton button)
        {
            switch (deviceNumber)
            {
                case 0:
                    _InputOneBuffer &= (byte)~((byte)(1 << ((byte)button - 1)));

                    break;
                case 1:
                    _InputTwoBuffer |= (byte)(1 << ((byte)button - 1));
                    break;
                case 2:
                    _InputThreeBuffer |= (byte)(1 << ((byte)button - 1));
                    break;
                case 3:
                    _InputFourBuffer |= (byte)(1 << ((byte)button - 1));
                    break;
                default:
                    throw new ArgumentOutOfRangeException("deviceNumber");
            }

#if DEBUG 
            TraceLogger.TraceInformation(TraceSubsystem.Controller,
                "Input Buffer Write : Device {0} Button : {1}",
                deviceNumber,
                button
            );
#endif
        }

        protected void AttachDevice(NesInputDeviceType deviceType)
        {
            //_RegisterOne.SetSignature(DeviceSettings.
        }

        /// <summary>
        /// Called when [machine attached].
        /// </summary>
        protected override void OnMachineAttached()
        {
            if ( NesHost == null )
            {
                _RegisterOne = null;
                _RegisterTwo = null;
            }
            else
            {
                _RegisterOne = NesHost.Machine.Controller.PortOne;
                _RegisterTwo = NesHost.Machine.Controller.PortTwo;

                _NesMachineHost.Machine.Controller.PortOne.SetSignature(NesInputDeviceType.StandardController);
            }

        }
        #endregion Methods

    }
}
